package com.dy.design_pattern_study.observer_mode.dome3;

import com.dy.design_pattern_study.observer_mode.dome3.notifier_code.impl.ConcreteSubject;
import com.dy.design_pattern_study.observer_mode.dome3.observer_code.impl.ConcreteObserver;

/**
 * @CreateBy zhangdingyi
 * @Date 2023-04-04
 * @Content 观察者模式又叫做发布-订阅（Publish/Subscribe）模式
 * 观察者模式定义了一种一对多的依赖关系，让多个观察者对象同时监听某一个主题对象。
 * 这个主题对象在状态发生变化时，会通知所有观察者对象，使它们能够自动更新自己
 * 简单的讲，就是 A发布信息 并 通知 B执行
 *
 * 疑惑：为上面前面的dome使用接口，而这里使用抽象类？
 * 其实抽象类和接口都差不多，这里之所以用抽象类，是因为继承
 * 前面学习模板方法的时候，就得注意到，这里有通用的方法，因此为了避免代码冗余
 * 就统一使用抽象类。
 * 但这仅仅是对于本案例，实际上还需要根据实际情况进行分析，到底使用接口还是抽象类
 * 如果使用接口的话，就可以应付不同的类（不管什么杂七杂八的类都能使用接口，但继承就规定是仅某一种类）
 *
 * 那么在什么地方使用呢？
 * 将一个系统分割成一系列相互协作的类有一个很不好的副作用，那就是需要维护相关对象间的一致性。
 * 我们不希望为了维持一致性而使各类紧密耦合，这样会给维护、扩展和重用都带来不便
 * 简单的说，就是 A 执行的时候，需要 B 一起来执行才能达到效果，这时候就会在 A 中调用 B。
 * 如果 A 调用不仅仅是 B、还有C、D、E 那么就会引起极大的耦合，因此在A改变的时候，
 * 就会直接通知到 B、C、D、E一起执行，这样耦合性就会极大的降低
 * 也就是 当一个对象的改变需要同时改变其他对象，但不知道到底有多少个具体的对象时
 */
public class Client {
    public static void main(String[] args) {

        /*
         * 这个观察者模式实际上也是很好的使用了依赖倒转
         *
         * 观察者模式所做的工作其实就是在解除耦合。
         * 让耦合的双方都依赖于抽象，而不是依赖于具体。
         * 从而使得各自的变化都不会影响另一边的变化。
         *
         * 就是具体的类都是依赖于抽象，而不是具体的类
         *
         * 那么从哪里可以看出这个是依赖于抽象呢？
         * 1.可以先看看两个实体类，里面的内容都是独立存在的，仅与抽象类有关系
         * 2.在抽象类中，又是接口的互相调用，仅做到依赖接口而不是依赖具体的实现类
         *
            这里现有两个抽象类，抽象类集合公用的方法
            Subject 是 通知抽象类 -可以添加、删除、通知 观察者类
            ConcreteSubject 是 具体的通知类

            Observer 是 观察者抽象类 -可以更新观察者实体的状态
            ConcreteObserver 是 具体的观察者类

            具体的工作流程
            1.ConcreteSubject 通知类添加需要添加的观察者对象
            2.ConcreteSubject 设置消息
            3.ConcreteSubject 发送消息
            4.ConcreteObserver 对象接收到消息，再对具体类的状态进行修改
            那么 简单的说，就是通知类，通知 观察者类，然后观察者类的状态改变，这个就是观察者模式
         */
        //通知者类
        ConcreteSubject s = new ConcreteSubject();

        //添加观察者类
        s.Attach(new ConcreteObserver("X", s));
        s.Attach(new ConcreteObserver("Y", s));
        s.Attach(new ConcreteObserver("Z", s));

        //设置状态
        s.setSubjectState("ABC");

        //发送通知
        s.Notify();
    }
}
